/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sg.edu.nus.iss.pacman.ui;

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.Displayable;
import sg.edu.nus.iss.pacman.game.PacManGame;
import sg.edu.nus.iss.pacman.game.Game;
import sg.edu.nus.iss.pacman.*;
import java.util.Timer;
import java.util.TimerTask;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.game.GameCanvas;
import sg.edu.nus.iss.pacman.game.Player;
import sg.edu.nus.iss.pacman.midlet.PacManScreen;

/**
 * A UI class for Pac-Man.
 * @author fredy
 */
public class PacManUI extends GameCanvas implements Game, CommandListener
{
    private PacManScreen screen;
    private boolean gameOver = false;
    private boolean win = false;
    private PacManGame pacManGame;
    private MazeBuilder mazeBuilder;
    private Timer pacManTimer;
    private TimerTask pacManTimerTask;
    private int pacManTimerDelay = 160;
    private Timer ghostTimer;
    private TimerTask ghostTimerTask;
    private int ghostTimerDelay = 320;
    private Thread pacManThread;
    private static final int SLEEP = 30;
    private boolean pacManStarted;
    private boolean ghostStarted;
    private Command cmdExit;
    private Command cmdOK;

    /**
     * Performs something when game over.
     */
    public void gameOver()
    {
        ghostTimer.cancel();
        pacManTimer.cancel();
        gameOver = true;
    }

    /**
     * Performs something when win.
     */
    public void win()
    {
        ghostTimer.cancel();
        pacManTimer.cancel();
        win = true;
    }

    /**
     * Crates a new instance of PacManUI.
     * @param pacMan the PacManScreen
     */
    public PacManUI(PacManScreen pacMan)
    {
        super(false);
        this.screen = pacMan;
        init(null);
    }

    /**
     * Creates a new instance of PacManUI.
     * @param pacMan the PacManScreen
     * @param maze the maze
     */
    public PacManUI(PacManScreen pacMan, int[][] maze)
    {
        super(false);
        this.screen = pacMan;
        init(maze);
    }

    private void init(int[][] maze)
    {
        setTitle("Pac-Man");
        pacManGame = new PacManGame(this, maze);
        mazeBuilder = new MazeBuilder(getWidth(), getHeight(),
            pacManGame.getPacMan(), pacManGame.getGhosts());
        mazeBuilder.setGraphics(getGraphics());
        pacManTimerTask = new TimerTask()
        {
            public void run()
            {
                pacManGame.movePacMan();
            }
        };
        pacManTimer = new Timer();
        ghostTimer = new Timer();
        ghostTimerTask = new TimerTask()
        {
            public void run()
            {
                pacManGame.moveGhost();
            }
        };
        cmdExit = new Command("Exit", Command.EXIT, 2);
        cmdOK = new Command("OK", Command.OK, 2);
        addCommand(cmdExit);
        setCommandListener(this);
    }

    /**
     * Exits the game when the exit command is triggered.
     * @param c the Command
     * @param d the Displayable
     */
    public void commandAction(Command c, Displayable d)
    {
        if (c == cmdExit)
        {
            screen.displayMainMenu();
        }
        else if (c == cmdOK)
        {
            screen.displayUserProfile();
        }
    }

    class PacManRunnable implements Runnable
    {
        public void run()
        {
            if (!ghostStarted)
            {
                ghostTimer.schedule(ghostTimerTask, 0, ghostTimerDelay);
                ghostStarted = true;
            }

            while (true)
            {
                drawScore();
                drawMaze();
                checkUserInput();
                flushGraphics();

                try
                {
                    Thread.sleep(SLEEP);
                }
                catch (InterruptedException ex)
                {
                    ex.printStackTrace();
                }

                if (gameOver || win)
                {
                    if (gameOver)
                    {
                        mazeBuilder.getGraphics().setColor(ColorConstants.YELLOW);
                        mazeBuilder.getGraphics().drawString("GAME OVER!",
                            getWidth() / 2, getHeight() / 2, Graphics.BASELINE | Graphics.HCENTER);
                    }
                    else
                    {
                        if (win)
                        {
                            mazeBuilder.getGraphics().setColor(ColorConstants.YELLOW);
                            mazeBuilder.getGraphics().drawString("YOU WIN!",
                                getWidth() / 2, getHeight() / 2, Graphics.BASELINE | Graphics.HCENTER);
                        }
                    }
                    flushGraphics();
                    break;
                }
            }
            screen.completeGame(pacManGame.getTotalScore());
            addCommand(cmdOK);
        }

        private void drawScore()
        {
            mazeBuilder.getGraphics().setColor(ColorConstants.BLUE);
            mazeBuilder.getGraphics().fillRect(0, 0, getWidth(), getHeight());
            int totalScore = pacManGame.getTotalScore();
            mazeBuilder.getGraphics().setColor(ColorConstants.YELLOW);
            mazeBuilder.getGraphics().drawString("Score: " + totalScore, 0, 15,
                Graphics.LEFT | Graphics.BASELINE);
        }

        private void drawMaze()
        {
            mazeBuilder.draw(pacManGame.getMaze());
        }

        private void checkUserInput()
        {
            int keyStates = getKeyStates();
            if (!win && !gameOver)
            {
                if (keyStates == LEFT_PRESSED)
                {
                    pacManGame.getPacMan().setPosition(Player.LEFT);
                    if (!pacManStarted)
                    {
                        pacManTimer.schedule(pacManTimerTask, 0, pacManTimerDelay);
                        pacManStarted = true;
                    }
                }
                else if (keyStates == RIGHT_PRESSED)
                {
                    pacManGame.getPacMan().setPosition(Player.RIGHT);
                    if (!pacManStarted)
                    {
                        pacManTimer.schedule(pacManTimerTask, 0, pacManTimerDelay);
                        pacManStarted = true;
                    }
                }
                else if (keyStates == UP_PRESSED)
                {
                    pacManGame.getPacMan().setPosition(Player.UP);
                    if (!pacManStarted)
                    {
                        pacManTimer.schedule(pacManTimerTask, 0, pacManTimerDelay);
                        pacManStarted = true;
                    }
                }
                else if (keyStates == DOWN_PRESSED)
                {
                    pacManGame.getPacMan().setPosition(Player.DOWN);
                    if (!pacManStarted)
                    {
                        pacManTimer.schedule(pacManTimerTask, 0, pacManTimerDelay);
                        pacManStarted = true;
                    }
                }
            }
        }
    }

    /**
     * Called when the game started.
     */
    protected void showNotify()
    {
        pacManThread = new Thread(new PacManRunnable());
        pacManThread.start();
    }
}
